package org.unidata.mdm.rest.v1.meta.service.model;

import java.io.IOException;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.server.standard.SpringConfigurator;
import org.unidata.mdm.system.util.JsonUtils;

/**
 * endpoint for working with web sockets.
 *
 * @author Alexandr Serov
 * @since 20.07.2020
 **/
@ServerEndpoint(value = "/v1/websocket", configurator = SpringConfigurator.class)
public class ImportMetaModelWebSocketEndpoint {

    private static final Logger LOG = LoggerFactory.getLogger(ImportMetaModelWebSocketService.class);

    /**
     * Static list of open connections to implement self-registration support
     */
    private static final Set<ImportMetaModelWebSocketEndpoint> endpoints = new CopyOnWriteArraySet<>();

    /**
     * Endpoint session
     */
    private Session session;

    /**
     * Send message to all active connections
     *
     * @param message message to sent
     */
    public static void broadcastMetaModelMessage(MetaModelMessage message) {
        Objects.requireNonNull(message, "MetaModelMessage can't be null");
        final String json = JsonUtils.write(message);
        endpoints.forEach(endpoint -> {
            synchronized (endpoint) {
                try {
                    RemoteEndpoint.Basic remote = endpoint.session.getBasicRemote();
                    remote.sendText(json);
                } catch (Exception ex) {
                    LOG.error("Dispatch meta model message error", ex);
                }
            }
        });
    }

    @OnMessage
    public void monitor(Session session, String sessionId) throws IOException {
        broadcastMetaModelMessage(new MetaModelMessage());
    }

    @OnOpen
    public void onOpen(Session session) throws IOException {
        this.session = session;
        endpoints.add(this);
    }

    @OnClose
    public void onClose(Session session) throws IOException {
        endpoints.remove(this);
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        // Do error handling here
    }

    /**
     * Metamodel message
     */
    public static class MetaModelMessage implements Serializable {
        private String type;

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
    }

}
